/*
 * Copyright(c) 2023 NeatLogic Co., Ltd. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package neatlogic.module.report.widget;

import com.alibaba.fastjson.JSONObject;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
import neatlogic.framework.report.exception.ReportDrawBarFieldLessAttrException;
import neatlogic.framework.report.exception.ReportDrawBarLessAttrException;
import neatlogic.framework.report.exception.ReportDrawBarLessFieldException;
import neatlogic.module.report.util.JfreeChartUtil;
import neatlogic.module.report.util.JfreeChartUtil.ChartColor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.ui.TextAnchor;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DatasetUtils;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class DrawStackedBar implements TemplateMethodModelEx {
	private static final Log logger = LogFactory.getLog(DrawStackedBar.class);
	private final String actionType;
	//报表中所有数据源
	private Map<String, Object> reportMap;

    public DrawStackedBar(Map<String, Object> reportMap, String actionType) {
        this.reportMap = reportMap;
        this.actionType = actionType;
    }
    @Override
	public Object exec(List arguments) throws TemplateModelException {
		boolean canReturn = true;
		int width = 1000;
		int height = 400;
		int tick = 0;
		String title = "", xLabel = "", yLabel = "", data = "";
		boolean isShowValue = true;

		CategoryDataset dataset = null;

		if (arguments.size() >= 1) {
			String config = arguments.get(0).toString();
			try {
				JSONObject configObj = JSONObject.parseObject(config);
				data = configObj.getString("data");
				title = configObj.getString("title");
				xLabel = configObj.getString("xLabel");
				yLabel = configObj.getString("yLabel");
				if (configObj.getIntValue("width") > 0) {
					width = configObj.getIntValue("width");
				}
				if (configObj.getIntValue("height") > 0) {
					height = configObj.getIntValue("height");
				}
				tick = configObj.getIntValue("tick");
				if (configObj.containsKey("isShowValue")) {
					isShowValue = configObj.getBooleanValue("isShowValue");
				}
			} catch (Exception ex) {
				// 非json格式
			    logger.error(ex.getMessage(), ex);
			}
		}

		List<Map<String, Object>> tbodyList = (List<Map<String, Object>>) reportMap.get(data);
		if (CollectionUtils.isNotEmpty(tbodyList)) {
			List<String> rowList = new ArrayList<>();
			List<String> columnList = new ArrayList<>();
			double[][] dataList = new double[tbodyList.size()][];
			int i = 0;
			for (Map<String, Object> tbody : tbodyList) {
				Object groupField = tbody.get("groupField");
				if (groupField != null) {
					rowList.add(groupField.toString());
				} else {
					throw new ReportDrawBarLessFieldException("groupField");
				}
				List<Map<String, Object>> valueItemList = (List<Map<String, Object>>) tbody.get("dataList");
				if (CollectionUtils.isNotEmpty(valueItemList)) {
					double[] dList = new double[valueItemList.size()];
					int j = 0;
					for (Map<String, Object> valueItem : valueItemList) {
						String typeField = (String) valueItem.get("typeField");
						if (typeField != null) {
							if (!columnList.contains(typeField)) {
								columnList.add(typeField);
							}
						} else {
							throw new ReportDrawBarFieldLessAttrException("dataList", "typeField");
						}
						Object valueField = valueItem.get("valueField");
						if (valueField != null) {
							dList[j] = Double.parseDouble(valueField.toString());
						} else {
							throw new ReportDrawBarFieldLessAttrException("dataList", "valueField");
						}
						j++;
					}
					dataList[i] = dList;
				} else {
					throw new ReportDrawBarLessAttrException("dataList");
				}
				i++;
			}
			dataset = DatasetUtils.createCategoryDataset(rowList.toArray(new String[0]), columnList.toArray(new String[0]), dataList);
		}
		StandardChartTheme standardChartTheme = JfreeChartUtil.getStandardChartTheme(actionType);

		JFreeChart chart = ChartFactory.createStackedBarChart(title, xLabel, yLabel, dataset);
		standardChartTheme.apply(chart);
		chart.getLegend().setFrame(new BlockBorder(ChartColor.CHART_BACKGROUND_COLOR.getColor(actionType)));

		CategoryPlot p = chart.getCategoryPlot();
		CategoryItemRenderer renderer = new DrawStackedBar.CustomRenderer(actionType);
		renderer.setDefaultItemLabelsVisible(isShowValue);
		p.setRenderer(renderer);
		p.setOutlinePaint(Color.white);
		p.setNoDataMessage("无数据");
		CategoryAxis axis = p.getDomainAxis();// X坐标轴
		axis.setLowerMargin(0);
		axis.setUpperMargin(0);
		axis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);// 倾斜45度
		if (tick > 0) {
			List<String> xLables = dataset.getColumnKeys();
			for (int k = 0; k < xLables.size(); k++) {
				if (k % tick != 0) {
					axis.setTickLabelPaint(xLables.get(k), Color.WHITE);
				}
			}
		}
		return JfreeChartUtil.getChartString(actionType, chart, width, height);

	}

	static class CustomRenderer extends StackedBarRenderer {
		private static final long serialVersionUID = 3946096994457346387L;
		private final Paint[] colors;

		public CustomRenderer(String actionType) {
			this.setBarPainter(new StandardBarPainter());
			this.setShadowVisible(false);
			setDefaultShadowsVisible(false);
			this.setDefaultItemLabelsVisible(true);
			this.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
			this.setDefaultPositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));
			this.setItemLabelAnchorOffset(-10D);
			this.colors = JfreeChartUtil.getCharColors(actionType);
			// this.setDefaultItemLabelFont(new Font("黑体", Font.PLAIN,
			// ReportConfig.JFREECHART_FONTSIZE + 2));
		}

		public Paint getItemPaint(final int row, final int column) {
			return (this.colors[row % this.colors.length]);
		}

		public LegendItem getLegendItem(int dataset, int series) {
			LegendItem legendItem = super.getLegendItem(dataset, series);
			legendItem.setFillPaint(this.colors[series % this.colors.length]);
			return legendItem;
		}
	}
}
